<?php

namespace App\Api\Controllers\CustomerApplets;

use App\Api\Controllers\CustomerApplets\AesUtilController;
use EasyWeChat\Factory;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\DB;
use App\Api\Controllers\CustomerApplets\BaseController;
use App\Models\CustomerAppletsCoupons;
use App\Models\CustomerAppletsAliPayCoupons;
use App\Models\CustomerAppletsCouponUsers;
use App\Models\WechatCashCouponConfig;
use App\Models\WechatMerchantCashCouponConfig;

use GuzzleHttp\Exception\RequestException;
use think\Exception;
use think\response\Redirect;
use WechatPay\GuzzleMiddleware\WechatPayMiddleware;
use WechatPay\GuzzleMiddleware\Util\PemUtil;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Client;

class CouponController extends BaseController
{
    /**
     * 介绍：
     * 以下接口规则是根据微信支付券最新的规则: WechatPay-API-v3
     * 微信官方说明：https://wechatpay-api.gitbook.io/wechatpay-api-v3/
     *
     * 证书类型有两种，这两种证书的类型概念要弄懂
     * |----商户api证书
     *
     * |----微信支付平台证书
     *
     * 使用到的第三方sdk中间件：wechatpay-guzzle-middleware
     * github地址：https://github.com/wechatpay-apiv3/wechatpay-guzzle-middleware
     */

    /**
    //商户号
    protected $merchantId       = '348313801';
    //请求方式
    protected $http_method      = ['GET','POST','PUT'];
    //商户api证书序列号
    protected $serial_no        = "146177D7E613DA60119B2FDA4DBBCC023C0458FE";
    //商户api私钥证书路径
    protected $privateKeyPath   = "cert/348313801/apiclient_key.pem";
    //微信支付平台证书,在WechatPay-API-v3规则下，请求接口获取的
    //连接地址：https://wechatpay-api.gitbook.io/wechatpay-api-v3/jie-kou-wen-dang/ping-tai-zheng-shu
    protected $weChatPayCertificateKeyPath = "cert/348313801/348313801_weChatPay_cert.pem";
    //认证类型，目前为WECHATPAY2-SHA256-RSA2048
    protected $schema           = 'WECHATPAY2-SHA256-RSA2048';
    //APIv2密钥，V2签名规则,生成签名,商户api密钥key，需要登录微信支付平台管理进行设置
    protected $key_v2           = "9231258F888B6B221F95AE345CB709A7";
    //APIv3密钥，需要登录微信支付平台管理进行设置
    protected $key_v3           = "jF9BYdcmbqXiotrC87G0vwHxgRy6VL2P";
    **/

    //商户号
    protected $merchantId;
    //请求方式
    protected $http_method  = ['GET','POST','PUT'];
    //商户api证书序列号
    protected $serial_no;
    //商户api私钥证书路径
    protected $privateKeyPath;
    //微信支付平台证书,在WechatPay-API-v3规则下，请求接口获取的
    //连接地址：https://wechatpay-api.gitbook.io/wechatpay-api-v3/jie-kou-wen-dang/ping-tai-zheng-shu
    protected $weChatPayCertificateKeyPath;
    //认证类型，目前为WECHATPAY2-SHA256-RSA2048
    protected $schema       = 'WECHATPAY2-SHA256-RSA2048';
    //APIv2密钥，V2签名规则,生成签名,商户api密钥key，需要登录微信支付平台管理进行设置
    protected $key_v2;

    public function __construct()
    {
        $wechatMerchantModel = new WechatMerchantCashCouponConfig();
        $data = $wechatMerchantModel->getInfo();

        $this->merchantId           = $data->merchant_id;
        $this->serial_no            = $data->api_serial_no;
        $this->privateKeyPath       = $data->key_path;
        $this->weChatPayCertificateKeyPath = $data->wechat_pay_certificate_key_path;
        $this->key_v2               = $data->api_v2_secret;

        // $this->merchantId           = config('api.merchantId');
        // $this->serial_no            = config('api.serial_no');
        // $this->privateKeyPath       = config('api.privateKeyPath');
        // $this->weChatPayCertificateKeyPath = config('api.weChatPayCertificateKeyPath');
        // $this->key_v2               = config('api.key_v2');
    }

    /**
	 * 生成随机字符串
	 * @date 2019-05-20
	 */
    public function rand_code()
    {
        $str = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';//62个字符
        $str = str_shuffle($str);
        $str = substr($str,0,32);
        return $str;
    }

    /**
     * url query生成器
     * @param $url
     * @param $query
     * @return string
     */
    public function getUrlQuery($url,$query){
        $urlQuery = http_build_query($query);
        return $url."?".$urlQuery;
    }

    /**
     * 生成请求参数中用到的参数项out_request_no
     * @return string
     */
    public function getOutRequestNo(){
        return $this->merchantId.date("Ymd",time()).rand(10000,99999);
    }

    /**
     * 改版
     * 生成请求参数中用到的参数项out_request_no
     * @return string
     */
    public function getOutRequestNoNew($merchantId){
        return $merchantId.date("Ymd",time()).rand(10000,99999);
    }

    /**
     * rfc3339标准格式转换成普通日期格式
     * rfc3339标准格式为YYYY-MM-DDTHH:mm:ss+TIMEZONE，YYYY-MM-DD表示年月日，
     * T出现在字符串中，表示time元素的开头，HH:mm:ss表示时分秒，TIMEZONE表示时区（+08:00表示东八区时间，领先UTC 8小时，即北京时间）
     */
    public function timezoneTransformationDate($timezone){
        $date = strtotime($timezone);
        $date = date("Y-m-d H:i:s",$date);
        return $date;
    }

    /**
     * 成普通日期格式转换rfc3339标准格式
     * rfc3339标准格式为YYYY-MM-DDTHH:mm:ss+TIMEZONE，YYYY-MM-DD表示年月日，
     * T出现在字符串中，表示time元素的开头，HH:mm:ss表示时分秒，TIMEZONE表示时区（+08:00表示东八区时间，领先UTC 8小时，即北京时间）
     */
    public function dateTransformationTimezone($date){
        date_default_timezone_set("UTC");
        $gmDate = strtotime($date);
        $gmDate = gmdate("Y-m-dTH:i:s+08:00",$gmDate);
        $gmDate = str_replace("GM","",$gmDate);
        return $gmDate;
    }

    /**
     * 计算两个日期差多少天
     * @param $date1 开始日期
     * @param $date2 结束日期
     * @return float
     */
    public function getChaBetweenTwoDate($date1,$date2){
        $diffTime = strtotime($date2) - strtotime($date1);
        $day      = $diffTime/(3600*24);
        return $day;
    }

    /**
     * 获取商户api私钥内容
     * @param $filepath
     * @return bool|resource
     */
    public function getPrivateKey($filepath) {
        return openssl_get_privatekey(file_get_contents($filepath));
    }

    /**
     * 获取请求微信支付券的请求头
     * @param $schema
     * @param $token
     * @return array
     */
    public function getRequestHeader($schema,$token){
        //下面这四项都是必须要有的
        $header = array(
            "Accept: application/json",
            "Content-Type: application/json",
            "User-Agent:".$_SERVER['HTTP_USER_AGENT'],
            'Authorization: '.$schema.' '.$token
        );
        return $header;
    }

    /**
     * 生成签名，并且组合成Authorization,返回出去
     * @param $url
     * @param $http_method
     * @param $body
     * @return array
     */
    public function getSign($url,$http_method,$body,$input = []){
        $merchantId     = isset($input['wx_merchant_id']) ? $input['wx_merchant_id'] : $this->merchantId;
        $api_serial_no  = isset($input['api_serial_no']) ? $input['api_serial_no'] : $this->serial_no;
        $key_path       = isset($input['key_path']) ? $input['key_path'] : $this->privateKeyPath;
        $timestamp      = time();
        $nonce          = $this->rand_code();
        $mch_private_key = $this->getPrivateKey($key_path);
        $url_parts       = parse_url($url);
        $canonical_url   = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : ""));
        $message         = $http_method."\n". $canonical_url."\n". $timestamp."\n". $nonce."\n". $body."\n";

        openssl_sign($message, $raw_sign, $mch_private_key, 'sha256WithRSAEncryption');

        $sign   = base64_encode($raw_sign);

        $token  = sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"', $merchantId, $nonce, $timestamp, $api_serial_no, $sign);

        $authorization = $this->getRequestHeader($this->schema,$token);

        return $authorization;
    }

    /**
     * 获取平台证书列表,并且生成证书保存在系统平台,
     * 这里需要用到APIV3密钥
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function certificates(Request $request){
        try {
            $input = $request->all();
            $merchantId = $input['wx_merchant_id'];

            $url         = "https://api.mch.weixin.qq.com/v3/certificates";
            $http_method = $this->http_method[0];
            $body        = "";
            $authorizationHeader = $this->getSign($url,$http_method,$body,$input);
            $result = $this->curl_get_https($url,$authorizationHeader);
            $response_data = json_decode($result,true);

            if(!empty($response_data['code'])){
                return $this->responseDataJson(202,$response_data['message'],"");
            }else{
                $encrypt_certificate = $response_data['data'][0]['encrypt_certificate'];
                $aesUtilController = new AesUtilController($input['api_v3_secret']);
                $result = $aesUtilController->decryptToString($encrypt_certificate['associated_data'],$encrypt_certificate['nonce'],$encrypt_certificate['ciphertext']);

                if (!file_exists("cert/".$merchantId)) {
                    mkdir("cert/".$merchantId,0777,true);
                }

                $path = "cert/".$merchantId."/".$merchantId."_weChatPay_cert.pem";

                if($result){
                    // 同步

                    file_put_contents($path, $result);
                    return $this->responseDataJson(200,"请求成功", $path);
                } else {
                    return $this->responseDataJson(202,"请求失败");
                }
            }
        } catch (\Exception $e) {
            return $this->sys_response(2002, $e->getMessage());
        }
    }

    /**
     * 在微信小程序中，用户领取该微信支付商家券使用的加密签名
     * V2签名规则,生成签名
     * @param $params      加密的参数数据
     * @param string $type 加密类型
     * @return string
     */
    private function getWeChatPaySign($params,$type = "MD5")
    {
        //将参数数组按照参数名ASCII码从小到大排序
        ksort($params);
        foreach ($params as $key => $item) {
            //剔除参数值为空的参数
            if (!empty($item)) {
                //整合新的参数数组
                $newArr[] = $key.'='.$item;
            }
        }
        //使用 & 符号连接参数
        $stringA = implode("&", $newArr);
        //拼接key
        $stringSignTemp = $stringA."&key=".$this->key_v2;
        //key是在商户平台API安全里自己设置的
        if($type == "MD5"){
            //将字符串进行MD5加密
            $stringSignTemp = md5($stringSignTemp);
        }else{
            //将字符串进行sha256加密
            $stringSignTemp = hash_hmac("sha256",$stringSignTemp ,$this->key_v2);
        }
        //将所有字符转换为大写
        $sign = strtoupper($stringSignTemp);
        return $sign;
    }

    /**
     * 创建微信支付商家券
     * 微信支付券：
     * |--微信支付代金券
     * |--微信支付商家券
     * 微信小程序中使用微信支付券插件的时候，只能在商家券进行发券
     * 商家劵不能再支付的时候使用劵，必须先核销之后，商户再判断这个劵满多少减多少。再付多少钱。支付劵是可以的。然后商家劵的核销以及其他规则是由商户自己去搞定的，代金券是微信支付帮忙做的。适合的场景也就不一样。
     * 商家券，需要先手动核销，然后付款的时候减掉券的金额，剩下的是顾客需要付的钱；代金券是自动核销；所以说商家券和公众号里的代金券没有两样，一个逻辑，对于商户和顾客来讲使用起来都非常麻烦。
     *
     *
     * 当前仅支持商家券，暂不支持微信支付代金券
     * 微信小程序接入微信商家券文档连接地址：https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/miniprogram/chapter1_1.shtml
     * 微信支付商家券文档地址：https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/busifavor/chapter3_1.shtml
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function createWeChatPayStoreCoupon(Request $request){
        $requestAllData = $request->all();

        if(!isset($requestAllData['store_id']) || empty($requestAllData['store_id'])){
            return $this->responseDataJson(202,"门店id参数不可为空");
        }

        if(!isset($requestAllData['available_begin_time']) || empty($requestAllData['available_begin_time'])){
            return $this->responseDataJson(202,"开始时间不可为空");
        }

        if(!isset($requestAllData['available_end_time']) || empty($requestAllData['available_end_time'])){
            return $this->responseDataJson(202,"结束时间不可为空");
        }

        if(!isset($requestAllData['discount_amount']) || empty($requestAllData['discount_amount'])){
            return $this->responseDataJson(202,"优惠金额不可为空");
        }

        if(!isset($requestAllData['transaction_minimum']) || empty($requestAllData['transaction_minimum'])){
            return $this->responseDataJson(202,"消费门槛不可为空");
        }

        $storeInfo = DB::table("merchant_store_appid_secrets")->where(['store_id' => $requestAllData['store_id']])->first();

        if(empty($storeInfo)){
            return $this->responseDataJson(202,"该门店appid信息不存在");
        }

        // 获取门店微信商户号
        $wechatStores = DB::table("merchant_store_appid_secrets")->where(['store_id' => $requestAllData['store_id']])->first();
        $wx_sub_merchant_id = $wechatStores->wx_sub_merchant_id;

        // 商户号
        $merchantId             = $this->merchantId;
        // 商户API证书序列号
        $merchantSerialNumber   = $this->serial_no;
        // 商户私钥
        $merchantPrivateKey     = PemUtil::loadPrivateKey($this->privateKeyPath);
        // 微信支付平台证书
        $wechatpayCertificate   = PemUtil::loadCertificate($this->weChatPayCertificateKeyPath);

        // 构造一个WechatPayMiddleware
        $wechatpayMiddleware = WechatPayMiddleware::builder()
            // 传入商户相关配置
            ->withMerchant($merchantId, $merchantSerialNumber, $merchantPrivateKey)
            // 可传入多个微信支付平台证书，参数类型为array
            ->withWechatPay([ $wechatpayCertificate ])
            ->build();

        $stack = HandlerStack::create();
        $stack->push($wechatpayMiddleware, 'wechatpay');

        $client = new Client(['handler' => $stack]);

        try {
            $out_request_no       = $this->getOutRequestNo();
            $available_begin_time = $this->dateTransformationTimezone($requestAllData['available_begin_time']);
            $available_end_time   = $this->dateTransformationTimezone($requestAllData['available_end_time']);

            $couponData['store_id']                 = $requestAllData['store_id'];
            $couponData['coupon_stock_name']        = isset($requestAllData['coupon_stock_name']) ? $requestAllData['coupon_stock_name']:"商家券";
            // $couponData['coupon_belong_merchant']   = $this->merchantId;
            $couponData['coupon_belong_merchant']   = $wx_sub_merchant_id;
            $couponData['coupon_comment']           = isset($requestAllData['coupon_stock_name']) ? $requestAllData['coupon_stock_name']:"商家券";
            $couponData['goods_name']               = "单品使用";
            $couponData['coupon_stock_type']        = "NORMAL";
            $couponData['out_request_no']           = $out_request_no;
            $couponData['coupon_code_mode']         = "WECHATPAY_MODE";
            $couponData['available_begin_time']     = $available_begin_time;
            $couponData['available_end_time']       = $available_end_time;
            $couponData['discount_amount']          = intval($requestAllData['discount_amount']);
            $couponData['transaction_minimum']      = intval($requestAllData['transaction_minimum']);
            $couponData['use_method']               = "MINI_PROGRAMS";
            $couponData['mini_programs_appid']      = $storeInfo->wechat_appid;
            $couponData['mini_programs_path']       = "/pages/index/index?store_id=".$requestAllData['store_id'];
            $couponData['max_amount']               = intval($requestAllData['max_amount']);
            $couponData['max_coupons']              = intval($requestAllData['max_coupons']);
            $couponData['max_coupons_per_user']     = 1;
            //计算两个时间段中的天数
            $diffDay = $this->getChaBetweenTwoDate($requestAllData['available_begin_time'],$requestAllData['available_end_time']);
            //进行请求
            $resp = $client->request('POST', 'https://api.mch.weixin.qq.com/v3/marketing/busifavor/stocks', [
                'json' => [
                    //JSON请求体
                    'stock_name'      => $couponData['coupon_stock_name'],
                    // 'belong_merchant' => $this->merchantId,
                    'belong_merchant' => $wx_sub_merchant_id,
                    'comment'         => $couponData['coupon_comment'],
                    'goods_name'      => $couponData['goods_name'],
                    'stock_type'      => $couponData['coupon_stock_type'],
                    'coupon_use_rule' => [
                        'coupon_available_time'     => [
                            'available_begin_time'  => $couponData['available_begin_time'],
                            'available_end_time'    => $couponData['available_end_time'],
                            'available_day_after_receive' => $diffDay + 5,//生效后N天内有效
                        ],
                        'fixed_normal_coupon' => [
                            'discount_amount'     => intval($couponData['discount_amount']) * 100,
                            'transaction_minimum' => intval($couponData['transaction_minimum']) * 100,
                        ],
                        'use_method'          => $couponData['use_method'],
                        'mini_programs_appid' => $couponData['mini_programs_appid'],
                        'mini_programs_path'  => $couponData['mini_programs_path'],
                    ],
                    'stock_send_rule'   => [
                        'max_amount'            => intval($couponData['max_amount']) * 100,
                        'max_coupons'           => $couponData['max_coupons'],
                        'max_coupons_per_user'  => $couponData['max_coupons_per_user'],
                    ],
                    'out_request_no'    => $out_request_no,
                    'custom_entrance'   => [
                        'mini_programs_info' => [
                            'mini_programs_appid' => $couponData['mini_programs_appid'],
                            'mini_programs_path'  => $couponData['mini_programs_path'],
                            'entrance_words'      => '欢迎选购'
                        ]
                    ],
                    'coupon_code_mode' => $couponData['coupon_code_mode']
                ],
                'headers' => ['Accept' => 'application/json']
            ]);
            $coupon = json_decode($resp->getBody(),true);
            Log::info("创建卡券：".json_encode($coupon));
            log::info("卡券号：".$out_request_no);
            if(isset($coupon['stock_id']) && !empty($coupon['stock_id'])){
                $couponData['stock_id']                 = $coupon['stock_id'];
                $couponData['available_begin_time']     = $requestAllData['available_begin_time'];
                $couponData['available_end_time']       = $requestAllData['available_end_time'];
                date_default_timezone_set("Asia/Shanghai");
                $couponData['created_at']               = $this->timezoneTransformationDate($coupon['create_time']);
                //创建卡券数据
                $customerAppletsCouponsModel = new CustomerAppletsCoupons();

                $result = $customerAppletsCouponsModel->createCoupon($couponData);

                if($result['status'] == 200){
                    return $this->responseDataJson($resp->getStatusCode(),$resp->getReasonPhrase(),$coupon);
                }else{
                    return $this->responseDataJson(202,$result['message'],"卡券数据存储失败");
                }
            }else{
                return $this->responseDataJson(202,"创建失败");
            }
        } catch (RequestException $e) {
            $errorData = json_decode($e->getResponse()->getBody(),true);
            return $this->responseDataJson($e->getResponse()->getStatusCode(),$errorData['message'],$errorData);
        }
    }

    /**
     * 查询门店下面的卡券数据（微信：微信支付商家券 支付宝：支付宝卡券）
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function getUserStoreCoupon(Request $request){
        $requestAllData = $request->all();
        if(!isset($requestAllData['store_id']) || empty($requestAllData['store_id'])){
            return $this->responseDataJson(202,"门店id参数不可为空");
        }

        if(!isset($requestAllData['terminal_type']) || empty($requestAllData['terminal_type'])){
            return $this->responseDataJson(202,"terminal_type参数不可为空");
        }

        //判断获取的是微信卡券还是支付宝的卡券
        switch ($requestAllData['terminal_type']) {

            case config("api.weChat"):
                //获取卡券数据
                $customerAppletsCouponsModel = new CustomerAppletsCoupons();
                $couponResult = $customerAppletsCouponsModel->getStoreCoupon($requestAllData['store_id'],isset($requestAllData['status']) ? $requestAllData['status']:"");
                if(!empty($requestAllData['user_id'])){
                    foreach ($couponResult as $key => $val){
                        $userCoupon = DB::table("customerapplets_coupon_users")->where(['user_id' => $requestAllData['user_id'],'store_id' => $requestAllData['store_id'],'stock_id' => $val->stock_id])->first();
                        if($userCoupon){
                            $val->is_receive = true;
                        }else{
                            $val->is_receive = false;
                        }
                        $val->user_id = $requestAllData['user_id'];

                        $val->send_coupon_merchant = $this->merchantId;
                        $val->sign = $this->getWeChatPaySign([
                            'send_coupon_merchant' => $this->merchantId,
                            'stock_id0'            => $val->stock_id,
                            'out_request_no0'      => $val->out_request_no
                        ],"SHA256");
                        $val->send_coupon_params = [[
                            'stock_id' => $val->stock_id,
                            'out_request_no' => $val->out_request_no
                        ]];
                    }
                }else{
                    foreach ($couponResult as $key => $val){
                        $val->user_id = "";
                    }
                }
                return $this->responseDataJson(200,"查询成功",$couponResult);
                break;

            case config("api.aliPay"):
                //获取卡券数据
                $customerAppletsAliPayCouponsModel = new CustomerAppletsAliPayCoupons();
                $couponResult = $customerAppletsAliPayCouponsModel->getStoreCoupon($requestAllData['store_id'],isset($requestAllData['status']) ? $requestAllData['status']:"");
                if(!empty($requestAllData['user_id'])){
                    foreach ($couponResult as $key => $val){
                        $userCoupon = DB::table("customerapplets_coupon_users")->where(['user_id' => $requestAllData['user_id'],'store_id' => $requestAllData['store_id'],'stock_id' => $val->tpl_id])->first();
                        if($userCoupon){
                            $val->is_receive = true;
                        }else{
                            $val->is_receive = false;
                        }
                        $val->user_id = $requestAllData['user_id'];
                    }
                }else{
                    foreach ($couponResult as $key => $val){
                        $val->user_id = "";
                    }
                }
                return $this->responseDataJson(200,"查询成功",$couponResult);
                break;
        }
    }

    /**
     * 查询微信支付商家券详情API
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function getCouponDetail(Request $request){
        $requestAllData = $request->all();
        if(!isset($requestAllData['store_id']) || empty($requestAllData['store_id'])){
            return $this->responseDataJson(202,"门店id参数不可为空");
        }
        if(!isset($requestAllData['stock_id']) || empty($requestAllData['stock_id'])){
            return $this->responseDataJson(202,"stock_id参数不可为空");
        }
        $url         = "https://api.mch.weixin.qq.com/v3/marketing/busifavor/stocks/".$requestAllData['stock_id'];
        $http_method = $this->http_method[0];
        $body        = "";
        $authorizationHeader = $this->getSign($url,$http_method,$body);
        $result = $this->curl_get_https($url,$authorizationHeader);
        $response_data = json_decode($result,true);
        if(!empty($response_data['code'])){
            return $this->responseDataJson(202,$response_data['message'],"");
        }else{
            return $this->responseDataJson(200,"请求成功",$response_data);
        }
    }

    /**
     * 查询用户单张券详情API
     * 服务商可通过该接口查询微信用户卡包中某一张商家券的详情信息。
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function selectUserCouponStatusDetail(Request $request){
        $requestAllData = $request->all();
        if(!isset($requestAllData['store_id']) || empty($requestAllData['store_id'])){
            return $this->responseDataJson(202,"门店id参数不可为空");
        }
        if(!isset($requestAllData['user_id']) || empty($requestAllData['user_id'])){
            return $this->responseDataJson(202,"user_id参数不可为空");
        }

        $userCouponInfo = DB::table("customerapplets_coupon_users")->where(['id' => $requestAllData['coupon_user_id']])->first();

        if(empty($userCouponInfo)){
            return $this->responseDataJson(202,"领取卡券记录信息不存在");
        }

        $storeInfo = DB::table("merchant_store_appid_secrets")->where(['store_id' => $requestAllData['store_id']])->first();

        if(empty($storeInfo)){
            return $this->responseDataJson(202,"该门店appid信息不存在");
        }

        $userWeChatInfo = DB::table("customerapplets_user_wechats")->where(['user_id' => $requestAllData['user_id']])->first();

        if(empty($userWeChatInfo)){
            return $this->responseDataJson(202,"该用户信息不存在");
        }

        $appid = $storeInfo->wechat_appid;

        $openid = $userWeChatInfo->wechat_openid;

        $coupon_code = $userCouponInfo->coupon_code;

        $url         = "https://api.mch.weixin.qq.com/v3/marketing/busifavor/users/{$openid}/coupons/{$coupon_code}/appids/".$appid;
        $http_method = $this->http_method[0];
        $body        = "";
        $authorizationHeader = $this->getSign($url,$http_method,$body);
        $result = $this->curl_get_https($url,$authorizationHeader);
        $response_data = json_decode($result,true);
        if(!empty($response_data['code'])){
            return $this->responseDataJson(202,$response_data['message'],"");
        }else{
            return $this->responseDataJson(200,"请求成功",$response_data);
        }

    }

    /**
     * 保存用户领取微信支付商家卡券记录数据
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function userReceiveCoupon(Request $request){
        $requestAllData = $request->all();

        if(!isset($requestAllData['store_id']) || empty($requestAllData['store_id'])){
            return $this->responseDataJson(202,"门店id参数不可为空");
        }
        if(!isset($requestAllData['user_id']) || empty($requestAllData['user_id'])){
            return $this->responseDataJson(202,"用户id参数不可为空");
        }
        if(!isset($requestAllData['stock_id']) || empty($requestAllData['stock_id'])){
            return $this->responseDataJson(202,"stock_id参数不可为空");
        }
        if(!isset($requestAllData['coupon_code']) || empty($requestAllData['coupon_code'])){
            return $this->responseDataJson(202,"coupon_code参数不可为空");
        }

        $customerAppletsCouponUsersModel = new CustomerAppletsCouponUsers();

        $customerAppletsCouponUsersResult = $customerAppletsCouponUsersModel->createCouponUser($requestAllData);

        if($customerAppletsCouponUsersResult['status'] == 200){
            return $this->responseDataJson(200,"创建成功","");
        }else{
            return $this->responseDataJson(202,$customerAppletsCouponUsersResult['message'],"");
        }
    }

    /**
     * 获取用户已经领取的卡券
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function getUserCoupon(Request $request){
        $requestAllData = $request->all();
        if(!isset($requestAllData['store_id']) || empty($requestAllData['store_id'])){
            return $this->responseDataJson(202,"门店id参数不可为空");
        }
        if(!isset($requestAllData['user_id']) || empty($requestAllData['user_id'])){
            return $this->responseDataJson(202,"用户id参数不可为空");
        }

        if(!isset($requestAllData['status']) || empty($requestAllData['status'])){
            return $this->responseDataJson(202,"状态参数不可为空");
        }

        $storeInfo = DB::table("merchant_store_appid_secrets")->where(['store_id' => $requestAllData['store_id']])->first();

        if(empty($storeInfo)){
            return $this->responseDataJson(202,"该门店appid信息不存在");
        }

        $userWeChatInfo = DB::table("customerapplets_user_wechats")->where(['user_id' => $requestAllData['user_id']])->first();

        if(empty($userWeChatInfo)){
            return $this->responseDataJson(202,"该用户信息不存在");
        }

        $appid = $storeInfo->wechat_appid;

        $openid = $userWeChatInfo->wechat_openid;

        $customerAppletsCouponUsersModel = new CustomerAppletsCouponUsers();
        $customerAppletsCouponUsersResult = $customerAppletsCouponUsersModel->getUserCoupon($requestAllData['user_id'],$requestAllData['store_id'],$requestAllData['status'],isset($requestAllData['money']) ? $requestAllData['money']:"");

        $num = 0;

        //查询卡券是否还能继续使用的状态
        if(!empty($requestAllData['type']) && $requestAllData['type'] == "cart"){
            if(!empty($customerAppletsCouponUsersResult)){
                foreach ($customerAppletsCouponUsersResult as $key => $val){
                    $url         = "https://api.mch.weixin.qq.com/v3/marketing/busifavor/users/{$openid}/coupons/{$val->coupon_code}/appids/".$appid;
                    $http_method = $this->http_method[0];
                    $body        = "";
                    $authorizationHeader = $this->getSign($url,$http_method,$body);
                    $result = $this->curl_get_https($url,$authorizationHeader);
                    $response_data = json_decode($result,true);
                    if(!empty($response_data['code'])){
                        $val -> coupon_state = false;
                        $val -> coupon_text = "卡券已失效";
                    }else{
                        $coupon_state = $response_data['coupon_state'];
                        if($coupon_state == "SENDED"){
                            $num += 1;
                            $val -> coupon_state = true;
                        }else{
                            $val -> coupon_state = false;
                            if($coupon_state == "USED"){
                                $val -> coupon_text = "卡券已核销";
                            }else if($coupon_state == "EXPIRED"){
                                $val -> coupon_text = "卡券已过期";
                            }
                        }
                    }
                }
            }
        }

        $customerAppletsCouponUsersResult['can_num'] = $num;

        return $this->responseDataJson(200,"请求成功",$customerAppletsCouponUsersResult);
    }

    /**
     * 核销微信支付商家券
     * @param $receive_coupon_id
     * @param $store_id
     * @param $user_id
     * @return \Illuminate\Http\JsonResponse
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function userUseCoupon($receive_coupon_id,$store_id,$user_id){
        Log::info("已经进入核销：");
        // 商户号
        $merchantId             = $this->merchantId;
        // 商户API证书序列号
        $merchantSerialNumber   = $this->serial_no;
        // 商户私钥
        $merchantPrivateKey     = PemUtil::loadPrivateKey($this->privateKeyPath);
        // 微信支付平台证书
        $wechatpayCertificate   = PemUtil::loadCertificate($this->weChatPayCertificateKeyPath);

        // 构造一个WechatPayMiddleware
        $wechatpayMiddleware = WechatPayMiddleware::builder()
            // 传入商户相关配置
            ->withMerchant($merchantId, $merchantSerialNumber, $merchantPrivateKey)
            // 可传入多个微信支付平台证书，参数类型为array
            ->withWechatPay([ $wechatpayCertificate ])
            ->build();

        $stack = HandlerStack::create();
        $stack->push($wechatpayMiddleware, 'wechatpay');

        $client = new Client(['handler' => $stack]);
        $date   = date("Y-m-d H:i:s",time());

        try {

            $userCouponInfo = DB::table("customerapplets_coupon_users")->where(['id' => $receive_coupon_id])->first();

            if(empty($userCouponInfo)){
                return $this->responseDataJson(202,"领取卡券记录信息不存在");
            }

            $storeInfo = DB::table("merchant_store_appid_secrets")->where(['store_id' => $store_id])->first();

            if(empty($storeInfo)){
                return $this->responseDataJson(202,"该门店appid信息不存在");
            }

            $userWeChatInfo = DB::table("customerapplets_user_wechats")->where(['user_id' => $user_id])->first();

            if(empty($userWeChatInfo)){
                return $this->responseDataJson(202,"该用户信息不存在");
            }

            $appid = $storeInfo->wechat_appid;

            $openid = $userWeChatInfo->wechat_openid;

            $out_request_no = $this->getOutRequestNo();

            $resp = $client->request('POST', 'https://api.mch.weixin.qq.com/v3/marketing/busifavor/coupons/use', [
                'json' => [
                    //JSON请求体
                    'coupon_code'     => $userCouponInfo->coupon_code,
                    'stock_id'        => $userCouponInfo->stock_id,
                    'appid'           => $appid,
                    'use_time'        => $this->dateTransformationTimezone($date),
                    'use_request_no'  => $out_request_no,
                    'openid'          => $openid
                ],
                'headers' => ['Accept' => 'application/json']
            ]);
            $coupon = json_decode($resp->getBody(),true);
            Log::info(json_encode($coupon));
            if(isset($coupon['stock_id']) && !empty($coupon['stock_id'])){

                //数据库中进行修改核销状态
                $wechatpay_use_time = $this->timezoneTransformationDate($coupon['wechatpay_use_time']);

                $openid             = isset($coupon['openid']) ? $coupon['openid']:"";

                $customerAppletsCouponUsersModel  = new CustomerAppletsCouponUsers();

                $customerAppletsCouponUsersResult = $customerAppletsCouponUsersModel->userUseCoupon($receive_coupon_id,$wechatpay_use_time,$openid);

                if($customerAppletsCouponUsersResult['status'] == 200){
                    return $this->responseDataJson($resp->getStatusCode(),$resp->getReasonPhrase(),$coupon);
                }else{
                    return $this->responseDataJson(202,$customerAppletsCouponUsersResult['message'],"");
                }
            }else{
                return $this->responseDataJson(202,"核销失败");
            }
        } catch (RequestException $e) {
            $errorData = json_decode($e->getResponse()->getBody(),true);
            Log::info(json_encode($errorData));
            return $this->responseDataJson($e->getResponse()->getStatusCode(),$errorData['message'],$errorData);
        }
    }

    /**
     * （此段代码暂时没有用到，只是为了测试 获取微信支付券生成的签名）
     * 此方法是获取微信小程序客户端领取微信支付券用到签名sign,
     * 此签名与以上微信支付券签名不同,以上是WechatPay-API-v3,v3规则
     * 此签名：
     *  签名计算值
     *  签名方式：HMAC-SHA256。
     *  签名规则：详见《V2签名规则》
     *  地址：https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=4_3
     *
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function getWeChatPaySignMd5ANDHMACSHA256(Request $request){
        $requestAllData = $request->all();
        $data['send_coupon_merchant']  = $this->merchantId;
        $data['stock_id0']             = "1298280000000005";
        $data['out_request_no0']       = "15843469112020092433119";
        //将参与签名的数据保存到数组  注意：以上几个参数是追加到$data中的，$data中应该同时包含开发文档中要求必填的剔除sign以外的所有数据
        $sign = $this->getWeChatPaySign($data,"SHA256");//获取签名
        return $this->responseDataJson(200,"请求成功",$sign);
    }

    /**
     * 条件查询批次列表API
     * 通过此接口可查询多个批次的信息，包括批次的配置信息以及批次概况数据
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function getMchCoupon(Request $request){
        $input = $request->all();
        $client = $this->get_client();

        try {
            $resp = $client->request('GET', 'https://api.mch.weixin.qq.com/v3/marketing/favor/stocks?offset='.$input['offset'].'&limit=10&stock_creator_mchid='.$input['stock_creator_mchid'], [

                'headers' => ['Accept' => 'application/json']
            ]);
            return $this->responseDataJson($resp->getStatusCode(),$resp->getReasonPhrase(),json_decode($resp->getBody(),true));
        } catch (RequestException $e) {
            $errorData = json_decode($e->getResponse()->getBody(),true);
            return $this->responseDataJson($e->getResponse()->getStatusCode(),$errorData['message'],$errorData);
        }
    }

    /**
     * 获取微信支付券批次详情
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function getMchCouponDetail(Request $request){
        $input = $request->all();
        $url         = "https://api.mch.weixin.qq.com/v3/marketing/favor/stocks/" . $input['stock_id'];
        $query       = [
            'stock_creator_mchid' => $input['stock_creator_mchid']
        ];
        $url         = $this->getUrlQuery($url,$query);
        $http_method = $this->http_method[0];
        $body        = "";
        $authorizationHeader = $this->getSign($url,$http_method,$body);
        $result = $this->curl_get_https($url,$authorizationHeader);
        $response_data = json_decode($result,true);
        if(!empty($response_data['code'])){
            return $this->responseDataJson(202,$response_data['message'],"");
        }else{
            return $this->responseDataJson(200,"请求成功",$response_data);
        }
    }

    public function test_a(Request $request, $id)
    {
        $input = $request->all();
        echo $request->route('id');die;
        echo $id;die;
        $client = $this->get_client();

        // 接下来，正常使用Guzzle发起API请求，WechatPayMiddleware会自动地处理签名和验签
        try {
            $resp = $client->request('GET', 'https://api.mch.weixin.qq.com/v3/marketing/favor/stocks?offset='.$input['offset'].'&limit=10&stock_creator_mchid='.$input['stock_creator_mchid'], [

                'headers' => ['Accept' => 'application/json']
            ]);
            return $this->responseDataJson($resp->getStatusCode(),$resp->getReasonPhrase(),json_decode($resp->getBody(),true));
        } catch (RequestException $e) {
            $errorData = json_decode($e->getResponse()->getBody(),true);
            return $this->responseDataJson($e->getResponse()->getStatusCode(),$errorData['message'],$errorData);
        }
    }

    /**
     *（由于是微信支付代金券，暂时没有用到该段代码）
     * 发放代金券
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function userReceiveCoupons(Request $request){
        $input = $request->all();
        // 商户号
        $merchantId             = '348313801';
        echo $merchantId;
        // 商户API证书序列号
        $merchantSerialNumber   = '146177D7E613DA60119B2FDA4DBBCC023C0458FE';
        // 商户私钥
        $merchantPrivateKey     = PemUtil::loadPrivateKey('https://test.yunsoyi.cn/cert/348313801/apiclient_key.pem');
        // 微信支付平台证书
        $wechatpayCertificate   = PemUtil::loadCertificate('https://test.yunsoyi.cn/cert/348313801/348313801_weChatPay_cert.pem');

        // 构造一个WechatPayMiddleware
        $wechatpayMiddleware = WechatPayMiddleware::builder()
            ->withMerchant($merchantId, $merchantSerialNumber, $merchantPrivateKey) // 传入商户相关配置
            ->withWechatPay([ $wechatpayCertificate ]) // 可传入多个微信支付平台证书，参数类型为array
            ->build();

        // 将WechatPayMiddleware添加到Guzzle的HandlerStack中
        $stack = HandlerStack::create();
        $stack->push($wechatpayMiddleware, 'wechatpay');

        // 创建Guzzle HTTP Client时，将HandlerStack传入
        $client = new Client(['handler' => $stack]);

        // 接下来，正常使用Guzzle发起API请求，WechatPayMiddleware会自动地处理签名和验签
        try {
            $resp = $client->request('POST', 'https://api.mch.weixin.qq.com/v3/marketing/favor/users/'.$input['openid'].'/coupons', [
                'json' => [ //JSON请求体
                    'stock_id'            => $input['stock_id'],
                    // 'stock_creator_mchid' => $this->merchantId,
                    'stock_creator_mchid' => $merchantId,
                    // 'out_request_no'      => $this->merchantId.date("Ymd",time()).rand(10000,99999),
                    'out_request_no'      => $merchantId.date("Ymd",time()).rand(10000,99999),
                    'appid'               => $input['appid'],
                ],
                'headers' => ['Accept' => 'application/json']
            ]);
            return $this->responseDataJson($resp->getStatusCode(),$resp->getReasonPhrase(),json_decode($resp->getBody(),true));
        } catch (RequestException $e) {
            $errorData = json_decode($e->getResponse()->getBody(),true);
            return $this->responseDataJson($e->getResponse()->getStatusCode(),$errorData['message'],$errorData);
        }

    }

    /**
     * 创建微信支付代金券
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function createWeChatPayCashCoupon(Request $request){
        $requestAllData = $request->all();
        $user = $this->parseToken();
        $input['user_id'] = $user->user_id;

        // 根据门店id查询服务商user_id
        $storeInfo = DB::table("stores")->where(['store_id' => $requestAllData['store_id']])->first();
        if(empty($storeInfo)){
            return $this->responseDataJson(202,"该门店服务商信息不存在");
        }

        // 根据门店id查询商户号
        $wxStoreInfo = DB::table("weixin_stores")->where(['store_id' => $requestAllData['store_id']])->first();
        if(empty($wxStoreInfo)){
            return $this->responseDataJson(202,"该门店微信通道未开通");
        }

        // 根据服务商user_id查询服务商微信代金券配置参数
        $wechatCashCouponConfigModel = new WechatCashCouponConfig();
        $wechatCashCouponConfigInfo = $wechatCashCouponConfigModel->getWechatCashCouponConfig();
        if (empty($wechatCashCouponConfigInfo)) {
            return $this->responseDataJson(202,"服务商微信代金券参数未配置");
        }

        $wechatCashCouponConfigData['merchantId'] = $wechatCashCouponConfigInfo->wx_merchant_id;
        $wechatCashCouponConfigData['merchantSerialNumber'] = $wechatCashCouponConfigInfo->api_serial_no;
        $wechatCashCouponConfigData['merchantPrivateKey'] = $wechatCashCouponConfigInfo->key_path;
        $wechatCashCouponConfigData['wechatpayCertificate'] = $wechatCashCouponConfigInfo->wechat_pay_certificate_key_path;
        $merchantId = $wechatCashCouponConfigInfo->wx_merchant_id;

        // 构造微信请求client
        $client = $this->get_client($wechatCashCouponConfigData);

        // 查询本门店商户id
        $weixinStoreInfo = DB::table("weixin_stores")->where(['store_id' => $requestAllData['store_id']])->first();
        if(empty($weixinStoreInfo)){
            return $this->responseDataJson(202,"微信通道未开通");
        }

        try {
            $out_request_no       = $this->getOutRequestNoNew($wxStoreInfo->wx_sub_merchant_id);
            $available_begin_time = $this->dateTransformationTimezone($requestAllData['available_begin_time']);
            $available_end_time   = $this->dateTransformationTimezone($requestAllData['available_end_time']);
            $couponData['store_id']                 = $requestAllData['store_id'];
            $couponData['coupon_type']              = 2;
            $couponData['coupon_stock_name']        = isset($requestAllData['coupon_stock_name']) ? $requestAllData['coupon_stock_name'] : "代金券";
            // $couponData['coupon_belong_merchant']   = $this->merchantId;
            $couponData['coupon_belong_merchant']   = $wxStoreInfo->wx_sub_merchant_id;
            $couponData['coupon_comment']           = isset($requestAllData['coupon_comment']) ? $requestAllData['coupon_comment'] : "代金券";
            $couponData['goods_name']               = "单品使用";
            $couponData['coupon_stock_type']        = "NORMAL";
            $couponData['out_request_no']           = $out_request_no;
            $couponData['coupon_code_mode']         = "WECHATPAY_MODE";
            $couponData['available_begin_time']     = $available_begin_time;
            $couponData['available_end_time']       = $available_end_time;
            $couponData['discount_amount']          = $requestAllData['discount_amount'];
            $couponData['transaction_minimum']      = $requestAllData['transaction_minimum'];
            $couponData['use_method']               = 3;
            $couponData['max_amount']               = $requestAllData['max_coupons'] * $requestAllData['discount_amount'];
            $couponData['max_coupons']              = intval($requestAllData['max_coupons']);
            $couponData['max_coupons_per_user']     = intval($requestAllData['max_coupons_per_user']) ?? 1;
            $couponData['status']                   = 2;
            // $couponData['max_amount_by_day']        = isset($requestAllData['max_amount_by_day']) ? intval($requestAllData['max_amount_by_day']) : 1000;

            //进行请求
            $resp = $client->request('POST', 'https://api.mch.weixin.qq.com/v3/marketing/favor/coupon-stocks', [
                'json' => [
                    'stock_name'      => $couponData['coupon_stock_name'],
                    'belong_merchant' => $merchantId,
                    'comment'         => $couponData['coupon_comment'],
                    'available_begin_time' => $available_begin_time,
                    'available_end_time' => $available_end_time,
                    'stock_use_rule'     => [
                        'max_coupons'  => $couponData['max_coupons'], // 总数量
                        'max_amount'  => $couponData['max_coupons'] * $couponData['discount_amount'] * 100, // 总预算
                        // 'max_amount_by_day'  => $couponData['max_amount_by_day'],
                        'max_coupons_per_user'  => $couponData['max_coupons_per_user'],
                        'natural_person_limit'  => false,
                        'prevent_api_abuse'  => false,
                    ],
                    'coupon_use_rule' => [
                        'fixed_normal_coupon' => [
                            'coupon_amount'     => $couponData['discount_amount'] * 100,
                            'transaction_minimum' => $couponData['transaction_minimum'] * 100,
                        ],
                        'available_merchants' => [
                            $weixinStoreInfo->wx_sub_merchant_id
                        ],
                    ],
                    'no_cash' => true,
                    'stock_type' => 'NORMAL',
                    'out_request_no' => $out_request_no
                ],
                'headers' => ['Accept' => 'application/json']
            ]);
            $coupon = json_decode($resp->getBody(),true);

            if(isset($coupon['stock_id']) && !empty($coupon['stock_id'])){
                $couponData['stock_id']                 = $coupon['stock_id'];
                $couponData['available_begin_time']     = $requestAllData['available_begin_time'];
                $couponData['available_end_time']       = $requestAllData['available_end_time'];
                date_default_timezone_set("Asia/Shanghai");
                $couponData['created_at']               = $this->timezoneTransformationDate($coupon['create_time']);

                //创建卡券数据
                $customerAppletsCouponsModel = new CustomerAppletsCoupons();

                $result = $customerAppletsCouponsModel->createCoupon($couponData);

                if($result['status'] == 200){
                    // 直接激活
                    $userStartCouponsData['user_id'] = $input['user_id'];
                    $userStartCouponsData['wx_merchant_id'] = $wechatCashCouponConfigData['merchantId'];
                    $userStartCouponsData['stock_id'] = $coupon['stock_id'];
                    $this->userStartCoupons($userStartCouponsData);

                    // return $this->responseDataJson($resp->getStatusCode(),$resp->getReasonPhrase(),$coupon);
                    return $this->responseDataJson(1,'创建成功',$coupon);
                }else{
                    return $this->responseDataJson(202,"卡券数据存储失败");
                }
            }else{
                return $this->responseDataJson(202,"创建失败");
            }
        } catch (RequestException $e) {
            // $errorData = json_decode($e->getResponse()->getBody(),true);
            // return $this->responseDataJson($e->getResponse()->getStatusCode(),$errorData['message'],$errorData);
            return $this->responseDataJson(202,$e->getMessage());
        }
    }

    /**
     * 激活代金券批次API
     * @param  $input
     * @return \Illuminate\Http\JsonResponse
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function userStartCoupons($input){
        $merchantId = $input['wx_merchant_id'];
        if (empty($merchantId)) {
            return $this->responseDataJson(202,"服务商号不能为空");
        }

        // 构造client
        $client_data = $this->get_client_data($input);
        $client = $this->get_client($client_data);

        try {
            $resp = $client->request('POST', 'https://api.mch.weixin.qq.com/v3/marketing/favor/stocks/'.$input['stock_id'].'/start', [
                'json' => [ // JSON请求体
                    'stock_creator_mchid' => $merchantId,
                ],
                'headers' => ['Accept' => 'application/json']
            ]);
            return $this->responseDataJson($resp->getStatusCode(),$resp->getReasonPhrase(),json_decode($resp->getBody(),true));
        } catch (RequestException $e) {
            $errorData = json_decode($e->getResponse()->getBody(),true);
            return $this->responseDataJson($e->getResponse()->getStatusCode(),$errorData['message'],$errorData);
        }
    }

    /**
     * 构造get_client所需参数
     */
    public function get_client_data($input)
    {
        // 根据服务商user_id查询服务商微信代金券配置参数
        $wechatCashCouponConfigModel = new WechatCashCouponConfig();
        $wechatCashCouponConfigInfo = $wechatCashCouponConfigModel->getWechatCashCouponConfig($input);
        if (empty($wechatCashCouponConfigInfo)) {
            return $this->responseDataJson(202,"服务商微信代金券参数未配置");
        }

        $wechatCashCouponConfigData['merchantId'] = $wechatCashCouponConfigInfo->wx_merchant_id;
        $wechatCashCouponConfigData['merchantSerialNumber'] = $wechatCashCouponConfigInfo->api_serial_no;
        $wechatCashCouponConfigData['merchantPrivateKey'] = $wechatCashCouponConfigInfo->key_path;
        $wechatCashCouponConfigData['wechatpayCertificate'] = $wechatCashCouponConfigInfo->wechat_pay_certificate_key_path;

        return $wechatCashCouponConfigData;
    }

    /**
     * 构造微信代金券所需client
     */
    public function get_client($input)
    {
        // 商户号
        $merchantId             = $input['merchantId'];
        // 商户API证书序列号
        $merchantSerialNumber   = $input['merchantSerialNumber'];
        // 商户私钥
        $merchantPrivateKey     = PemUtil::loadPrivateKey($input['merchantPrivateKey']);
        // $merchantPrivateKey     = \openssl_get_privatekey(\file_get_contents($input['merchantPrivateKey']));
        // 微信支付平台证书
        $wechatpayCertificate   = PemUtil::loadCertificate($input['wechatpayCertificate']);
        // $wechatpayCertificate   = \openssl_x509_read(\file_get_contents($input['wechatpayCertificate']));

        // 构造一个WechatPayMiddleware
        $wechatpayMiddleware = WechatPayMiddleware::builder()
            ->withMerchant($merchantId, $merchantSerialNumber, $merchantPrivateKey) // 传入商户相关配置
            ->withWechatPay([ $wechatpayCertificate ]) // 可传入多个微信支付平台证书，参数类型为array
            ->build();

        // 将WechatPayMiddleware添加到Guzzle的HandlerStack中
        $stack = HandlerStack::create();
        $stack->push($wechatpayMiddleware, 'wechatpay');

        // 创建Guzzle HTTP Client时，将HandlerStack传入
        $client = new Client(['handler' => $stack]);

        return $client;
    }

    /**
     * 设置回调地址
     */
    public function setNotifyUrl(Request $request)
    {
        $input = $request->all();
        $user = $this->parseToken();
        $input['user_id'] = $user->user_id;
        $url = $_SERVER["HTTP_HOST"];
        $merchantId = $input['wx_merchant_id'];
        if (empty($merchantId)) {
            return $this->responseDataJson(202,"服务商号不能为空");
        }

        // // 根据服务商user_id查询服务商微信代金券配置参数
        // $wechatCashCouponConfigModel = new WechatCashCouponConfig();
        // $wechatCashCouponConfigInfo = $wechatCashCouponConfigModel->getWechatCashCouponConfig($input);
        // if (empty($wechatCashCouponConfigInfo)) {
        //     return $this->responseDataJson(202,"服务商微信代金券参数未配置");
        // }
        //
        // $wechatCashCouponConfigData['merchantId'] = $wechatCashCouponConfigInfo->wx_merchant_id;
        // $wechatCashCouponConfigData['merchantSerialNumber'] = $wechatCashCouponConfigInfo->api_serial_no;
        // $wechatCashCouponConfigData['merchantPrivateKey'] = $wechatCashCouponConfigInfo->key_path;
        // $wechatCashCouponConfigData['wechatpayCertificate'] = $wechatCashCouponConfigInfo->wechat_pay_certificate_key_path;

        $wechatCashCouponConfigData['merchantId'] = $input['wx_merchant_id'];
        $wechatCashCouponConfigData['merchantSerialNumber'] = $input['merchantSerialNumber'];
        $wechatCashCouponConfigData['merchantPrivateKey'] = $input['merchantPrivateKey'];
        $wechatCashCouponConfigData['wechatpayCertificate'] = $input['wechatpayCertificate'];

        // 构造微信请求client
        $client = $this->get_client($wechatCashCouponConfigData);

        try {
            $resp = $client->request('POST', 'https://api.mch.weixin.qq.com/v3/marketing/favor/callbacks', [
                'json' => [ // JSON请求体
                    'mchid' => $merchantId,
                    'notify_url' => 'https://' . $url . '/api/customer/user/djqNotify/' . $merchantId,
                ],
                'headers' => ['Accept' => 'application/json']
            ]);
            return $this->responseDataJson($resp->getStatusCode(),$resp->getReasonPhrase(),json_decode($resp->getBody(),true));
        } catch (RequestException $e) {
            $errorData = json_decode($e->getResponse()->getBody(),true);
            return $this->responseDataJson($e->getResponse()->getStatusCode(),$errorData['message'],$errorData);
        }
    }

    /**
     * 代金券核销事件回调通知API
     */
    public function djqNotify(Request $request, $merchant_id)
    {
        // 接收微信发送的 post json 数据
        $content = $request->getContent();
        $content_data = json_decode($content,true);

        // 根据服务商号获取v3_key
        $input['wx_merchant_id'] = $merchant_id;
        $model = new WechatCashCouponConfig();
        $data = $model->getWechatCashCouponConfig($input);
        $api_v3_secret = $data->api_v3_secret;

        // 解密通知报文
        $resource = $content_data['resource'];
        $aesUtilController = new AesUtilController($api_v3_secret);
        $result_json = $aesUtilController->decryptToString($resource['associated_data'],$resource['nonce'],$resource['ciphertext']);
        $result = json_decode($result_json, true);

        // $file = '/upload/text/' . date('YmdHis', time()) . '.txt';
        // $path= public_path() . $file;
        // file_put_contents($path, $result_json);

        // 批次号
        $stock_id = $result['stock_id'];
        // coupon_id
        $coupon_id = $result['coupon_id'];
        // 代金券名称
        $coupon_name = $result['coupon_name'];
        // 领券时间
        $create_time = $this->timezoneTransformationDate($result['create_time']);
        // 使用状态
        $status = $result['status'];
        // 核销订单号
        $transaction_id = $result['consume_information']['transaction_id'];
        // 核销商户号
        $consume_mchid = $result['consume_information']['consume_mchid'];
        // 代金券面额
        $coupon_amount = $result['normal_coupon_information']['coupon_amount'];
        // 代金券门槛
        $transaction_minimum = $result['normal_coupon_information']['transaction_minimum'];

        // // 查询订单表
        // if (env('DB_D1_HOST')) {
        //     $Stores_obj = DB::connection("mysql_d1")->table('orders');
        // } else {
        //     $Stores_obj = DB::table('orders');
        // }
        // $obj = $Stores_obj->select(['total_amount', 'receipt_amount', 'buyer_pay_amount', 'mdiscount_amount', 'status'])
        //     ->where('trade_no', $transaction_id)
        //     ->where('pay_status', 1)->first();

        // // 订单支付成功更新优惠金额
        // if ($data) {
        //     // 商家优惠金额
        //     $mdiscount_amount = $coupon_amount / 100;
        //     // 实收金额
        //     $receipt_amount = $obj->total_amount - $mdiscount_amount;
        //     // 费率
        //     $rate = $data->rate;
        //     // 手续费
        //     $fee_amount =  $rate / 100 * $receipt_amount;
        //
        //     $update_data = [
        //         'receipt_amount' => $receipt_amount, // 商家实际收款金额
        //         'mdiscount_amount' => $mdiscount_amount, // 商家优惠金额
        //         'buyer_pay_amount' => $receipt_amount, // 买家付款金额
        //         'fee_amount' => $fee_amount, // 手续费
        //     ];
        //     $update_res = $obj->where('trade_no', $transaction_id)->update($update_data);
        // }

        $couponUserData =  DB::table("customerapplets_coupon_users")
            ->where('coupon_code', $coupon_id)->first();
        if ($couponUserData) {
            $coupon_update_res = DB::table("customerapplets_coupon_users")
                ->where('coupon_code', $coupon_id)
                ->update([
                    'is_use_coupon' => 1,
                    'coupon_name'           => $coupon_name,
                    'wechatpay_use_time'    => date("Y-m-d H:i:s",time()),
                    'updated_at'            => date("Y-m-d H:i:s",time()),
                    'status'                => $status,
                    'coupon_amount'         => $coupon_amount / 100,
                    'transaction_minimum'   => $transaction_minimum / 100,
                ]);
            if ($coupon_update_res) {
                echo 'SUCCESS';
            }
        }
    }

    /**
     * 微信代金券扫二维码领券授权
     */
    public function oauth(Request $request)
    {
        $input = $request->all();
        // 参数校验
        $check_data = [
            'user_id'                   => '服务商user_id',
            'stock_id'                  => '批次号',
            'store_id'                  => '门店id',
            'out_request_no'            => '商户单据号',
            'coupon_belong_merchant'    => '核销商户号',
        ];
        $check = $this->check_required($input, $check_data);
        if ($check) {
            return $this->sys_response(40000, $check);
        }

        // 根据服务商user_id查询服务商微信代金券配置参数
        $wechatCashCouponConfigModel = new WechatCashCouponConfig();
        $wechatCashCouponConfigInfo = $wechatCashCouponConfigModel->getWechatCashCouponConfig($input['user_id']);
        if (empty($wechatCashCouponConfigInfo)) {
            return $this->responseDataJson(202,"服务商微信代金券参数未配置");
        }

        // 根据store_id查询商户号
        $wxStoreInfo = DB::table("weixin_stores")->where(['store_id' => $input['store_id']])->first();
        if(empty($wxStoreInfo)){
            return $this->responseDataJson(202,"该门店微信通道未开通");
        }

        $out_request_no = $this->getOutRequestNoNew($wxStoreInfo->wx_sub_merchant_id);

        $app_id = $wechatCashCouponConfigInfo->appid;
        $secret = $wechatCashCouponConfigInfo->secret;
        $wx_merchant_id = $wechatCashCouponConfigInfo->wx_merchant_id;

        $sub_info_data = [
            'appid'                     => $app_id,
            'user_id'                   => $input['user_id'],
            'store_id'                  => $input['store_id'],
            'stock_id'                  => $input['stock_id'],
            'out_request_no'            => $out_request_no,
            'stock_creator_mchid'       => $wx_merchant_id,
            'coupon_belong_merchant'    => $input['coupon_belong_merchant'],
        ];
        $sub_info = base64_encode(json_encode((array)$sub_info_data));

        $config = [
            'app_id' => $app_id,
            'scope' => 'snsapi_base',
            'oauth' => [
                'scopes'        => ['snsapi_base'],
                'response_type' => 'code',
                'callback'      => url('api/customer/user/oauth_callback?sub_info=' . $sub_info . '&wx_AppId=' . $app_id . '&wx_Secret=' . $secret . ''),
            ],
        ];
        $app = Factory::officialAccount($config);
        $oauth = $app->oauth;

        return $oauth->redirect();
    }

    /**
     * 微信扫码回调
     * @param Request $request
     */
    public function oauth_callback(Request $request)
    {
        // 接收参数
        $input = $request->all();
        $sub_info_arr = json_decode(base64_decode((string)$input['sub_info']), true);

        // 授权码
        $code       = $request->get('code');
        $wx_AppId   = $request->get('wx_AppId');
        $wx_Secret  = $request->get('wx_Secret');

        // 微信配置参数
        $config = [
            'app_id'        => $wx_AppId,
            "secret"        => $wx_Secret,
            "code"          => $code,
            "grant_type"    => "authorization_code",
        ];

        $app        = Factory::officialAccount($config);
        $oauth      = $app->oauth;
        $user       = $oauth->user();
        $open_id    = $user->getId();

        if (empty($open_id)) {
            return $this->sys_response(202, '领取失败');
        }

        // 发放微信代金券
        $input['user_id'] = $sub_info_arr['user_id'];

        // 构造client
        $client_data = $this->get_client_data($input);
        $client = $this->get_client($client_data);

        try {
            $resp = $client->request('POST', 'https://api.mch.weixin.qq.com/v3/marketing/favor/users/' . $open_id . '/coupons', [
                'json' => [ // JSON请求体
                    'stock_id'              => $sub_info_arr['stock_id'],
                    'out_request_no'        => $sub_info_arr['out_request_no'],
                    'appid'                 => $wx_AppId,
                    'stock_creator_mchid'   => $sub_info_arr['stock_creator_mchid'],
                ],
                'headers' => ['Accept' => 'application/json']
            ]);

            if ($resp->getStatusCode() == 200) {
                $date_now = date("Y-m-d H:i:s",time());

                $resData = json_decode($resp->getBody(),true);

                $coupon_insert_res = DB::table("customerapplets_coupon_users")->insert([
                    'user_id'               => 0,
                    'openid'                => $open_id,
                    'store_id'              => $sub_info_arr['store_id'],
                    'coupon_type'           => 2,
                    'coupon_code'           => $resData['coupon_id'],
                    'stock_id'              => $sub_info_arr['stock_id'],
                    'consume_mchid'         => $sub_info_arr['coupon_belong_merchant'],
                    'is_use_coupon'         => 2,
                    'create_time'           => $date_now,
                    'status'                => 'SENDED',
                    'coupon_amount'         => 0,
                    'transaction_minimum'   => 0,
                    'coupon_name'           => '',
                    'wechatpay_use_time'    => $date_now,
                    'created_at'            => $date_now,
                    'updated_at'            => $date_now,
                ]);

                // return $this->responseDataJson($resp->getStatusCode(),$resp->getReasonPhrase(),json_decode($resp->getBody(),true));
                return view("webH5Mobile.couponSuccess");
            }
        } catch (RequestException $e) {
            $errorData = json_decode($e->getResponse()->getBody(),true);
            return $this->responseDataJson($e->getResponse()->getStatusCode(),$errorData['message'],$errorData);
        }

    }

    // 解析token
    public function analysisToken()
    {
        // 发放微信代金券
        $user = $this->parseToken();
        $user_id = $user->user_id;

        return $this->sys_response(1, '请求成功', $user_id);
    }

    // 微信代金券二维码
    public function couponQr(Request $request)
    {
        try {
            $input = $request->all();
            $user = $this->parseToken();
            if (!empty($user)) {
                $input['user_id'] = $user->user_id;
            } else {
                $input['user_id'] = 1234;
            }

            // 根据store_id查询商户号
            $wxStoreInfo = DB::table("weixin_stores")->where(['store_id' => $input['store_id']])->first();
            if(empty($wxStoreInfo)){
                return $this->responseDataJson(202,"该门店微信通道未开通");
            }

            $out_request_no = $this->getOutRequestNoNew($wxStoreInfo->wx_sub_merchant_id);

            $data = [
                'store_pay_qr' => url(
                    '/api/customer/user/oauth?stock_id=' . $input['stock_id'] . '&out_request_no=' . $out_request_no
                      . '&user_id=' . $input['user_id'] . '&store_id=' . $input['store_id']
                      . '&coupon_belong_merchant=' . $input['coupon_belong_merchant']
                ),
            ];

            return $this->sys_response(1, '操作成功', $data);
        } catch (\Exception $ex) {
            $this->status = -1;
            $this->message = $ex->getMessage().' | '.$ex->getFile().' | '.$ex->getLine();
            return $this->format();
        }
    }

    // 获取微信支付平台证书，并返回证书序列号
    public function getCertificates($input){
        try {
            $merchantId = $input['wx_merchant_id'];

            $url         = "https://api.mch.weixin.qq.com/v3/certificates";
            $http_method = $this->http_method[0];
            $body        = "";
            $authorizationHeader = $this->getSign($url,$http_method,$body,$input);
            $result = $this->curl_get_https($url,$authorizationHeader);
            $response_data = json_decode($result,true);

            if(!empty($response_data['code'])){
                return $this->responseDataJson(202,$response_data['message'],"");
            }else{
                $encrypt_certificate = $response_data['data'][0]['encrypt_certificate'];

                $aesUtilController = new AesUtilController($input['api_v3_secret']);

                $result = $aesUtilController->decryptToString($encrypt_certificate['associated_data'],$encrypt_certificate['nonce'],$encrypt_certificate['ciphertext']);

                if (!file_exists("cert/".$merchantId)) {
                    mkdir("cert/".$merchantId,0777,true);
                }

                $path = "cert/".$merchantId."/".$merchantId."_weChatPay_cert.pem";

                if($result){
                    file_put_contents($path, $result);
                    return $this->responseDataJson(200,"请求成功", $path);
                } else {
                    return $this->responseDataJson(202,"请求失败");
                }
            }
        } catch (\Exception $e) {
            return $this->sys_response(2002, $e->getMessage());
        }
    }

}
